From 98da41ff60f187be6e7906d61886410c4d565071 Mon Sep 17 00:00:00 2001 From: CGantert345 <57003061+CGantert345@users.noreply.github.com> Date: Fri, 20 May 2022 13:50:53 +0200 Subject: experimental implementation of Elliptic Curve Public Key Encoding with X9.62 compressed and uncompressed --- src/main/java/org/uic/barcode/Encoder.java | 25 ++ .../dynamicFrame/api/SimpleDynamicFrame.java | 10 +- .../java/org/uic/barcode/utils/ECKeyEncoder.java | 284 +++++++++++++++++++++ .../org/uic/barcode/utils/EllipticCurveNames.java | 67 +++++ .../java/org/uic/barcode/utils/SecurityUtils.java | 29 +-- .../org/uic/barcode/test/ECKeyEncoderTest.java | 227 ++++++++++++++++ 6 files changed, 610 insertions(+), 32 deletions(-) create mode 100644 src/main/java/org/uic/barcode/utils/ECKeyEncoder.java create mode 100644 src/main/java/org/uic/barcode/utils/EllipticCurveNames.java create mode 100644 src/test/java/org/uic/barcode/test/ECKeyEncoderTest.java diff --git a/src/main/java/org/uic/barcode/Encoder.java b/src/main/java/org/uic/barcode/Encoder.java index 9afddce..b01ca14 100644 --- a/src/main/java/org/uic/barcode/Encoder.java +++ b/src/main/java/org/uic/barcode/Encoder.java @@ -27,6 +27,7 @@ import org.uic.barcode.staticFrame.ticketLayoutBarcode.TicketLayout; import org.uic.barcode.ticket.EncodingFormatException; import org.uic.barcode.ticket.UicRailTicketCoder; import org.uic.barcode.ticket.api.spec.IUicRailTicket; +import org.uic.barcode.utils.ECKeyEncoder; /** @@ -278,6 +279,30 @@ public class Encoder { } } + /** + * Sets the level 2 algorithm Is. + * + * @param level2SigningAlg the level 2 signing algorithm (OID) + * @param level2KeyAlg the level 2 key algorithm (OID) + * @param publicKey the public key of the level 2 signature + * @param publicKeyEncodingFormat "X509", for elliptic curve keys only: "X962_UNCOMPRESSED", "X962_COMPRESSED" constants defined in class ECKeyEncoder. + **/ + public void setLevel2Algs(String level2SigningAlg, String level2KeyAlg, PublicKey publicKey, String publicKeyEncodingFormat) { + if (dynamicFrame != null) { + if (dynamicFrame.getLevel2Data() == null) { + dynamicFrame.setLevel2Data(new SimpleLevel2Data()); + } + if (dynamicFrame.getLevel2Data().getLevel1Data() == null) { + dynamicFrame.getLevel2Data().setLevel1Data(new SimpleLevel1Data()); + } + dynamicFrame.getLevel2Data().getLevel1Data().setLevel2SigningAlg(level2SigningAlg); + dynamicFrame.getLevel2Data().getLevel1Data().setLevel2KeyAlg(level2KeyAlg); + if (publicKey != null) { + dynamicFrame.getLevel2Data().getLevel1Data().setLevel2publicKey(ECKeyEncoder.getEncoded(publicKey, publicKeyEncodingFormat)); + } + } + } + public void setDynamicData(IUicDynamicContent content) throws EncodingFormatException { if (dynamicFrame != null) { if (dynamicFrame.getLevel2Data() == null) { diff --git a/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java b/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java index ae1b4e2..15f169b 100644 --- a/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java +++ b/src/main/java/org/uic/barcode/dynamicFrame/api/SimpleDynamicFrame.java @@ -8,8 +8,6 @@ import java.security.Provider; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; import java.util.Date; import org.uic.barcode.dynamicContent.api.DynamicContentCoder; @@ -20,6 +18,7 @@ import org.uic.barcode.dynamicFrame.v1.DynamicFrameCoderV1; import org.uic.barcode.dynamicFrame.v2.DynamicFrameCoderV2; import org.uic.barcode.ticket.EncodingFormatException; import org.uic.barcode.utils.AlgorithmNameResolver; +import org.uic.barcode.utils.ECKeyEncoder; import org.uic.barcode.utils.SecurityUtils; @@ -180,15 +179,12 @@ public class SimpleDynamicFrame implements IDynamicFrame { } KeyFactory keyFactory = KeyFactory.getInstance(keyAlgName,provider); if (keyFactory != null) { - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); - key = keyFactory.generatePublic(keySpec); + key = ECKeyEncoder.fromEncoded(keyBytes,level2KeyAlg, provider); } else { return Constants.LEVEL2_VALIDATION_KEY_ALG_NOT_IMPLEMENTED; } - } catch (InvalidKeySpecException e1) { - return Constants.LEVEL2_VALIDATION_KEY_ALG_NOT_IMPLEMENTED; - } catch (NoSuchAlgorithmException e1) { + } catch (Exception e1) { return Constants.LEVEL2_VALIDATION_KEY_ALG_NOT_IMPLEMENTED; } diff --git a/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java b/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java new file mode 100644 index 0000000..96038d3 --- /dev/null +++ b/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java @@ -0,0 +1,284 @@ +package org.uic.barcode.utils; + +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.Provider; +import java.security.PublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.EllipticCurve; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + + +public class ECKeyEncoder { + + + private static final byte X962_UNCOMPRESSED_POINT_INDICATOR = 0x04; + private static final byte X962_ODD = 0x02; + private static final byte X962_EVEN = 0x03; + + public static final String ENCODING_X509 = "X509"; + public static final String ENCODING_X962_UNCOMPESSED = "X962_UNCOMPRESSED"; + public static final String ENCODING_X962_COMPRESSED = "X962_COMPRESSED"; + + public static PublicKey fromEncoded (byte[] keyBytes, String oid, Provider provider) { + + PublicKey key = null; + + + String keyAlgName = null; + try { + keyAlgName = AlgorithmNameResolver.getName(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, oid,provider); + } catch (Exception e1) { + throw new IllegalArgumentException("algorithm unknown in: " + provider.getName()); + } + + if (keyAlgName == null || keyAlgName.length() == 0) { + throw new IllegalArgumentException("algorithm unknown in: " + provider.getName()); + } + + //try standard X.509 encoding first + + try { + + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + + if (keyAlgName != null && keyAlgName.length() > 0) { + + KeyFactory keyFactory = KeyFactory.getInstance(keyAlgName,provider); + + key = keyFactory.generatePublic(keySpec); + + } + + } catch (Exception e) { + + //try next option + + } + + if (key != null) return key; + + if (keyBytes[0] == X962_UNCOMPRESSED_POINT_INDICATOR) { + + + + } + + //maybe a compressed X9.62 eliptic key + if (keyBytes[0] == X962_ODD || keyBytes[0] == X962_EVEN) { + + + try { + + //we need to know the curve! + String curveName = EllipticCurveNames.getInstance().getName(oid); + + //get the curve parameters + AlgorithmParameters parameters = AlgorithmParameters.getInstance(keyAlgName, provider); + parameters.init(new ECGenParameterSpec(curveName)); + ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); + EllipticCurve curve = ecParameters.getCurve(); + + //reconstruct the uncompressed version with the curve + byte[] uncompressed = decompressPubkey(keyBytes, curve); + + //decode the uncompressed key + return fromUncompressedPoint(uncompressed, ecParameters); + + } catch (Exception e) { + key = null; + // failed + } + + + } + + //try X962 uncompressed + if (keyBytes[0] == X962_UNCOMPRESSED_POINT_INDICATOR) { + + try { + //we need to know the curve! + String curveName = EllipticCurveNames.getInstance().getName(oid); + + //get the curve parameters + AlgorithmParameters parameters = AlgorithmParameters.getInstance(keyAlgName, provider); + parameters.init(new ECGenParameterSpec(curveName)); + ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); + + //decode the uncompressed key + return fromUncompressedPoint(keyBytes, ecParameters); + + } catch(Exception e) { + //failed + } + } + + + throw new IllegalArgumentException("public key format unknown"); + } + + + + public static byte[] getEncoded(PublicKey key, String encoding){ + + if (encoding.equals(ENCODING_X509)) { + return key.getEncoded(); + } else if (encoding.equals(ENCODING_X962_UNCOMPESSED)) { + + if (key instanceof ECPublicKey) { + + return toUncompressedPoint((ECPublicKey) key); + + } + + } else if (encoding.equals(ENCODING_X962_COMPRESSED)) { + + if (key instanceof ECPublicKey) { + + ECPoint point = ((ECPublicKey) key).getW(); + + byte[] x = toUnsignedBytes(point.getAffineX()); + + BigInteger y = point.getAffineY(); + + byte[] compressed = new byte[x.length + 1]; + + //compression indicator + if (y.testBit(0)) { + compressed[0] = 0x03; + } else { + compressed[0] = 0x02; + } + System.arraycopy(x, 0, compressed, 1, x.length); + + return compressed; + } + } + + throw new IllegalArgumentException("unknown encoding"); + + + } + + + private static ECPublicKey fromUncompressedPoint( + final byte[] uncompressedPoint, final ECParameterSpec params) + throws Exception { + + int offset = 0; + if (uncompressedPoint[offset++] != X962_UNCOMPRESSED_POINT_INDICATOR) { + throw new IllegalArgumentException( + "Invalid uncompressedPoint encoding, no uncompressed point indicator"); + } + + int keySizeBytes = (params.getOrder().bitLength() + Byte.SIZE - 1) + / Byte.SIZE; + + if (uncompressedPoint.length != 1 + 2 * keySizeBytes) { + throw new IllegalArgumentException( + "Invalid uncompressedPoint encoding, not the correct size"); + } + + final BigInteger x = new BigInteger(1, Arrays.copyOfRange( + uncompressedPoint, offset, offset + keySizeBytes)); + offset += keySizeBytes; + final BigInteger y = new BigInteger(1, Arrays.copyOfRange( + uncompressedPoint, offset, offset + keySizeBytes)); + final ECPoint w = new ECPoint(x, y); + final ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(w, params); + final KeyFactory keyFactory = KeyFactory.getInstance("EC"); + return (ECPublicKey) keyFactory.generatePublic(ecPublicKeySpec); + } + + private static byte[] toUncompressedPoint(final ECPublicKey publicKey) { + + int keySizeBytes = (publicKey.getParams().getOrder().bitLength() + Byte.SIZE - 1) + / Byte.SIZE; + + final byte[] uncompressedPoint = new byte[1 + 2 * keySizeBytes]; + int offset = 0; + uncompressedPoint[offset++] = 0x04; + + final byte[] x = publicKey.getW().getAffineX().toByteArray(); + if (x.length <= keySizeBytes) { + System.arraycopy(x, 0, uncompressedPoint, offset + keySizeBytes + - x.length, x.length); + } else if (x.length == keySizeBytes + 1 && x[0] == 0) { + System.arraycopy(x, 1, uncompressedPoint, offset, keySizeBytes); + } else { + throw new IllegalStateException("x value is too large"); + } + offset += keySizeBytes; + + final byte[] y = publicKey.getW().getAffineY().toByteArray(); + if (y.length <= keySizeBytes) { + System.arraycopy(y, 0, uncompressedPoint, offset + keySizeBytes + - y.length, y.length); + } else if (y.length == keySizeBytes + 1 && y[0] == 0) { + System.arraycopy(y, 1, uncompressedPoint, offset, keySizeBytes); + } else { + throw new IllegalStateException("y value is too large"); + } + + return uncompressedPoint; + } + + static final BigInteger MODULUS = + new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16); + + static final BigInteger POW = MODULUS.add(BigInteger.ONE).shiftRight(2); + + // Given a 33-byte compressed public key, this returns a 65-byte uncompressed key. + private static byte[] decompressPubkey(byte[] compressedKey, EllipticCurve curve ) { + + // Check array length and type indicator byte + if (compressedKey.length != 33 || compressedKey[0] != 2 && compressedKey[0] != 3) + throw new IllegalArgumentException(); + + final byte[] xCoordBytes = Arrays.copyOfRange(compressedKey, 1, compressedKey.length); + final BigInteger xCoord = new BigInteger(1, xCoordBytes); // Range [0, 2^256) + + + BigInteger temp = xCoord.pow(2).add(curve.getA()); + temp = temp.multiply(xCoord); + temp = temp.add(curve.getB()); + temp = temp.modPow(POW, MODULUS); + + //temp = sqrtMod(temp.add(curveParamB)); + + boolean tempIsOdd = temp.testBit(0); + boolean yShouldBeOdd = compressedKey[0] == 3; + if (tempIsOdd != yShouldBeOdd) + temp = temp.negate().mod(MODULUS); + final BigInteger yCoord = temp; + + // Copy the x coordinate into the new + // uncompressed key, and change the type byte + byte[] result = Arrays.copyOf(compressedKey, 65); + result[0] = 0x04; + + // Carefully copy the y coordinate into uncompressed key + final byte[] yCoordBytes = yCoord.toByteArray(); + for (int i = 0; i < 32 && i < yCoordBytes.length; i++) + result[result.length - 1 - i] = yCoordBytes[yCoordBytes.length - 1 - i]; + + return result; + } + + private static byte[] toUnsignedBytes(BigInteger i) { + byte[] b = i.abs().toByteArray(); + //remove top sign bit + if (b[0] == 0) { + b = Arrays.copyOfRange(b, 1, b.length); + } + return b; + } + + +} diff --git a/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java b/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java new file mode 100644 index 0000000..41353b1 --- /dev/null +++ b/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java @@ -0,0 +1,67 @@ +package org.uic.barcode.utils; + +import java.util.HashMap; + +// TODO: Auto-generated Javadoc +/** + * The Class ElipticCurves. + */ +public class EllipticCurveNames { + + + /** The oit to name. */ + public HashMap oitToName = new HashMap(); + + /** The me. */ + private static EllipticCurveNames me = null; + + + /** + * Gets the single instance of ElipticCurves. + * + * @return single instance of ElipticCurves + */ + public static EllipticCurveNames getInstance() { + + if (me == null) { + me = new EllipticCurveNames(); + + me.oitToName.put("1.3.132.0.15", "sect163r2"); + me.oitToName.put("1.3.132.0.33", "secp224r1"); + me.oitToName.put("1.3.132.0.26", "sect233k1"); + me.oitToName.put("1.3.132.0.27", "sect233r1"); + me.oitToName.put("1.3.132.0.16", "sect283k1"); + me.oitToName.put("1.3.132.0.17", "sect283r1"); + me.oitToName.put("1.3.132.0.34", "secp384r1"); + me.oitToName.put("1.3.132.0.36", "sect409k1"); + me.oitToName.put("1.3.132.0.37", "sect409r1"); + me.oitToName.put("1.3.132.0.35", "secp521r1"); + me.oitToName.put("1.3.132.0.38", "sect571k1"); + me.oitToName.put("1.3.132.0.39", "sect571r1"); + me.oitToName.put("1.3.132.0.10", "secp256k1"); + + } + return me; + } + + + /** + * Adds the oid to name mapping. + * + * @param oid the oid + * @param name the name + */ + public void addOidToNameMapping(String oid, String name) { + oitToName.put(oid, name); + } + + /** + * Gets the name. + * + * @param oid the oid + * @return the name + */ + public String getName(String oid) { + return oitToName.get(oid); + } +} diff --git a/src/main/java/org/uic/barcode/utils/SecurityUtils.java b/src/main/java/org/uic/barcode/utils/SecurityUtils.java index fc6a135..5fdbda7 100644 --- a/src/main/java/org/uic/barcode/utils/SecurityUtils.java +++ b/src/main/java/org/uic/barcode/utils/SecurityUtils.java @@ -24,37 +24,16 @@ public class SecurityUtils { * @return the provider */ public static Provider findPublicKeyProvider(String keyAlgorithmOid, byte[] keyBytes) { - - - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); - - String name; - try { - name = AlgorithmNameResolver.getAlgorithmName(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, keyAlgorithmOid, null); - } catch (Exception e2) { - return null; - } - - KeyFactory keyFactory = null; - + Provider[] provs = Security.getProviders(); for (Provider provider : provs) { try { - keyFactory = KeyFactory.getInstance(name,provider); - } catch (NoSuchAlgorithmException e1) { + PublicKey key = ECKeyEncoder.fromEncoded(keyBytes, keyAlgorithmOid, provider); + if (key != null) return provider; + } catch (Exception e1) { //try next } - if (keyFactory != null) { - try { - keyFactory.generatePublic(keySpec); - return provider; - } catch (Exception e) { - provider = null; - //try next - } - } } - return null; } diff --git a/src/test/java/org/uic/barcode/test/ECKeyEncoderTest.java b/src/test/java/org/uic/barcode/test/ECKeyEncoderTest.java new file mode 100644 index 0000000..df8807e --- /dev/null +++ b/src/test/java/org/uic/barcode/test/ECKeyEncoderTest.java @@ -0,0 +1,227 @@ +package org.uic.barcode.test; + +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.util.Arrays; + +import org.bouncycastle.asn1.sec.SECNamedCurves; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Before; +import org.junit.Test; +import org.uic.barcode.utils.AlgorithmNameResolver; +import org.uic.barcode.utils.ECKeyEncoder; + +public class ECKeyEncoderTest { + + public static Provider provider = null; + + @Before public void initialize() { + + provider = new BouncyCastleProvider(); + Security.addProvider(provider); + } + + @Test public void testEncodeCompressed() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp256k1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); + + ECPublicKey key = createECPublicKey(name); + + // some additional encoding tricks + byte[] compressedBC = getCompressed(key,name); + String compressedHexBC = Hex.toHexString(compressedBC); + + byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_COMPRESSED); + String compressedHex = Hex.toHexString(publicKeyBytes); + + if (!compressedHexBC.equals(compressedHex)) { + assert(compressedHexBC.equals(compressedHex)); + } + + assert(Arrays.equals(compressedBC, publicKeyBytes)); + + assert(compressedHexBC.equals(compressedHex)); + } + } + + @Test public void testDecodeCompressed() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp256k1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); + + ECPublicKey key = createECPublicKey(name); + + // some additional encoding tricks + byte[] compressedBC = getCompressed(key,name); + //String compressedHex = Hex.toHexString(compressedBC); + + PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.10", provider); + + compareKeys((ECPublicKey) publicKey, key); + + } + } + + @Test public void testEncodeUnCompressed() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp256k1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); + + ECPublicKey key = createECPublicKey(name); + + byte[] uncompressedBC = getUnCompressed(key,name); + //String uncompressedHex = Hex.toHexString(uncompressedBC); + + byte[] publicKeyUnComp = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_UNCOMPESSED); + + assert(Arrays.equals(uncompressedBC, publicKeyUnComp)); + + } + } + + @Test public void testDecodeUnCompressed() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp256k1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); + + ECPublicKey key = createECPublicKey(name); + + // some additional encoding tricks + byte[] compressedBC = getUnCompressed(key,name); + //String compressedHex = Hex.toHexString(compressedBC); + + PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.10", provider); + + compareKeys((ECPublicKey) publicKey, key); + + } + } + + @Test public void testEncodeX509() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp256k1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); + + ECPublicKey key = createECPublicKey(name); + + byte[] publicKeyBcX509 = key.getEncoded(); + + byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X509); + assert(Arrays.equals(publicKeyBcX509, publicKeyBytes)); + + } + } + + @Test public void testDecodeX509() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp256k1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); + + ECPublicKey key = createECPublicKey(name); + + // some additional encoding tricks + byte[] compressedBC = key.getEncoded(); + //String compressedHex = Hex.toHexString(compressedBC); + + PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.10", provider); + + compareKeys((ECPublicKey) publicKey, key); + + } + } + + + + + private ECPublicKey createECPublicKey(String name) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + SecureRandom secureRandom = new SecureRandom(); + X9ECParameters secnamecurves = SECNamedCurves.getByName(name); + ECDomainParameters ecParams = new ECDomainParameters(secnamecurves.getCurve(), secnamecurves.getG(), + secnamecurves.getN(), secnamecurves.getH()); + ECKeyGenerationParameters keyGenParam = new ECKeyGenerationParameters(ecParams, secureRandom); + gen.init(keyGenParam); + + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC"); + ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256k1"); + kpg.initialize(ecGenParameterSpec); + ECPublicKey key = (ECPublicKey) kpg.generateKeyPair().getPublic(); + return key; + } + + private byte[] getCompressed(ECPublicKey key, String name) { + + byte[] x = key.getW().getAffineX().toByteArray(); + byte[] y = key.getW().getAffineY().toByteArray(); + + // assumes that x and y are (unsigned) big endian encoded + BigInteger xbi = new BigInteger(1, x); + BigInteger ybi = new BigInteger(1, y); + X9ECParameters x9 = ECNamedCurveTable.getByName(name); + ECCurve curve = x9.getCurve(); + ECPoint point = curve.createPoint(xbi, ybi); + + return point.getEncoded(true); + } + + private byte[] getUnCompressed(ECPublicKey key, String name) { + + byte[] x = key.getW().getAffineX().toByteArray(); + byte[] y = key.getW().getAffineY().toByteArray(); + + // assumes that x and y are (unsigned) big endian encoded + BigInteger xbi = new BigInteger(1, x); + BigInteger ybi = new BigInteger(1, y); + X9ECParameters x9 = ECNamedCurveTable.getByName(name); + ECCurve curve = x9.getCurve(); + ECPoint point = curve.createPoint(xbi, ybi); + + return point.getEncoded(false); + + } + + private void compareKeys(ECPublicKey key1, ECPublicKey key2) { + + assert(key1.getW().getAffineX().equals(key2.getW().getAffineX()) ); + assert(key1.getW().getAffineY().equals(key2.getW().getAffineY()) ); + + } + +} -- cgit v1.2.3 From dcb10e007cc46f627502ddd178b6f90a2d2c271c Mon Sep 17 00:00:00 2001 From: CGantert345 <57003061+CGantert345@users.noreply.github.com> Date: Fri, 20 May 2022 13:51:25 +0200 Subject: Create DecodeDB9EuroTicketTest.java --- .../ticketTestDB/DecodeDB9EuroTicketTest.java | 133 +++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 src/test/java/org/uic/barcode/ticketTestDB/DecodeDB9EuroTicketTest.java diff --git a/src/test/java/org/uic/barcode/ticketTestDB/DecodeDB9EuroTicketTest.java b/src/test/java/org/uic/barcode/ticketTestDB/DecodeDB9EuroTicketTest.java new file mode 100644 index 0000000..cc69aa0 --- /dev/null +++ b/src/test/java/org/uic/barcode/ticketTestDB/DecodeDB9EuroTicketTest.java @@ -0,0 +1,133 @@ +package org.uic.barcode.ticketTestDB; + + +import java.util.TimeZone; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.uic.barcode.Decoder; +import org.uic.barcode.asn1.uper.UperEncoder; +import org.uic.barcode.logger.LoggerFactory; +import org.uic.barcode.staticFrame.ticketLayoutBarcode.TicketLayout; +import org.uic.barcode.ticket.api.spec.IOpenTicket; +import org.uic.barcode.ticket.api.spec.IPassengerType; +import org.uic.barcode.ticket.api.spec.ITariff; +import org.uic.barcode.ticket.api.spec.ITrainLink; +import org.uic.barcode.ticket.api.spec.ITraveler; +import org.uic.barcode.ticket.api.spec.IUicRailTicket; + +public class DecodeDB9EuroTicketTest { + + TimeZone defaulttimeZone = null; + + /** + * Prepare tickets. + */ + @Before public void prepare() { + + LoggerFactory.setActivateConsoleLog(true); + + defaulttimeZone = TimeZone.getDefault(); + //decode in local CET time zone + TimeZone.setDefault(TimeZone.getTimeZone("CET")); + } + + + /** + * clean up + */ + @After public void resetTimeZone() { + TimeZone.setDefault(defaulttimeZone); + } + + @Test + public void testDecoder() throws Exception { + + + byte[] content = UperEncoder.bytesFromHexString(getEncodingV2Hex()); + + // try to decode + Decoder decoder = new Decoder(content); + TicketLayout layout = decoder.getLayout(); + IUicRailTicket ticket = decoder.getUicTicket(); + + + Assert.assertNotNull(ticket); + + Assert.assertNotNull(ticket.getDocumentData()); + Assert.assertNotNull(ticket.getIssuerDetails()); + Assert.assertNotNull(ticket.getTravelerDetails()); + + assert(ticket.getIssuerDetails().getIssuer().equals("1080")); + assert(ticket.getIssuerDetails().getIssuerPNR().equals("D260V48G")); + String issuingDate = ticket.getIssuerDetails().getIssuingDate().toString(); + assert(issuingDate.equals("Fri Oct 30 11:50:00 CET 2020")); + assert(ticket.getIssuerDetails().getSecurityProvider().equals("1080")); + assert(ticket.getIssuerDetails().isSecurePaperTicket() == false); + assert(ticket.getIssuerDetails().isActivated() == true); + assert(ticket.getIssuerDetails().isSpecimen() == false); + + assert(ticket.getTravelerDetails().getTravelers().size() == 1); + ITraveler traveler = ticket.getTravelerDetails().getTravelers().iterator().next(); + assert(traveler.getFirstName().equals("Karsten")); + assert(traveler.getLastName().equals("Will")); + assert(traveler.isTicketHolder() == true); + + assert(ticket.getDocumentData().size() == 1); + IOpenTicket openTicket = (IOpenTicket) ticket.getDocumentData().iterator().next(); + Assert.assertNotNull(openTicket.getValidRegionList()); + assert(openTicket.getReference().equals("CN0CTUMY")); + String fromDate = openTicket.getValidFrom().toString(); + assert(fromDate.equals("Thu Nov 05 00:00:00 CET 2020")); + assert(openTicket.getValidFromUTCoffset() == -4L); + String toDate = openTicket.getValidUntil().toString(); + assert(toDate.equals("Fri Nov 06 10:00:00 CET 2020")); + assert(openTicket.getValidUntilUTCoffset() == -4L); + + Assert.assertNotNull(openTicket.getTariffs()); + assert(openTicket.getTariffs().size() == 1); + ITariff tariff = openTicket.getTariffs().iterator().next(); + assert(tariff.getNumberOfPassengers() == 1); + assert(tariff.getPassengerType().equals(IPassengerType.adult)); + assert(tariff.getTariffDescription().equals("Super Sparpreis")); + + + ITrainLink tl = (ITrainLink) openTicket.getValidRegionList().iterator().next(); + Assert.assertNotNull(tl); + assert(tl.getTrain().equals("ICE973")); + String departureDate = tl.getDepartureDateTime().toString(); + assert(departureDate.equals("Fri Nov 06 11:58:00 CET 2020")); + Assert.assertNull(layout); + Assert.assertNotNull(decoder); + } + + public static String getEncodingV2Hex() { + + return "2355543032323038303030303033000000005C57C2"+ + "8521C3A1C3BCC29D5DC3960E2CC2897C18C390534"+ + "EC2AFC387C388703AC2B367C39FC3BD55C2B70000"+ + "0000422E1BC29F1CC3B9265E43C2B7493B2B51C39"+ + "2C291007CC2B5C2870D3A2EC3B3C38249C38FC2B3"+ + "3032343778C29C0BC28DC3B770757431303430303"+ + "53534343656400379C2A539394049132303232343"+ + "430353C283C3943CC2905068C2BCC29BC28F6B045"+ + "0C29BC291C28141C28101430AC3974C76C3BFC39C"+ + "C2BCC38CC292C38C420D2626090E064715C3AEC29"+ + "6060FC3A66E29C28D74C2BFC288C29277C391C2BB"+ + "C397C39DC289C2AC642E4A2D3978C39AC3ACC38D5"+ + "CC383C2A4C2AB0BC3B27CC396C38DC2B04CC2BB3B"+ + "79C2994EC3B4265EC3A7C28CC3845C1D05C2A7C38"+ + "4C28CC2BCC28CC3BC340108C38F2D27C3BFC3B0C3"+ + "BCC28CC384C2B4C394C2BC603D15C296C38606763"+ + "1C293C380C292C2B069C38FC297C2851D4B136B57"+ + "776209572F13336B370B7B16C2AEC2A032C3A508C"+ + "283C282C388C3846561C2B9C2B337255DC38D33C2"+ + "8BC29459C29B395B78C3AAC28EC399C39BC28E6D5"+ + "D17C2937BC38732C3A73CC2B73A6FC38BC29D1D45"+ + "4FC29BC2AEC3B1C38CC2B1C2883AC39B6CC38E7B6"+ + "D7B16030046115A6F"; + } + +} \ No newline at end of file -- cgit v1.2.3 From c9e083f171fd50ce055081f4c2b12377ac3e930d Mon Sep 17 00:00:00 2001 From: CGantert345 <57003061+CGantert345@users.noreply.github.com> Date: Mon, 23 May 2022 17:05:41 +0200 Subject: encoding of keys different from P-256 --- .../java/org/uic/barcode/utils/ECKeyEncoder.java | 187 ++++++++++------- .../org/uic/barcode/test/ECKeyEncoderTest521.java | 232 +++++++++++++++++++++ 2 files changed, 344 insertions(+), 75 deletions(-) create mode 100644 src/test/java/org/uic/barcode/test/ECKeyEncoderTest521.java diff --git a/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java b/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java index 96038d3..705b178 100644 --- a/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java +++ b/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java @@ -6,6 +6,7 @@ import java.security.KeyFactory; import java.security.Provider; import java.security.PublicKey; import java.security.interfaces.ECPublicKey; +import java.security.spec.ECFieldFp; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; import java.security.spec.ECPoint; @@ -15,17 +16,40 @@ import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; +// TODO: Auto-generated Javadoc +/** + * The Class ECKeyEncoder. + */ public class ECKeyEncoder { + /** The Constant X962_UNCOMPRESSED_POINT_INDICATOR. */ private static final byte X962_UNCOMPRESSED_POINT_INDICATOR = 0x04; + + /** The Constant X962_ODD. */ private static final byte X962_ODD = 0x02; + + /** The Constant X962_EVEN. */ private static final byte X962_EVEN = 0x03; + /** The Constant ENCODING_X509. */ public static final String ENCODING_X509 = "X509"; + + /** The Constant ENCODING_X962_UNCOMPESSED. */ public static final String ENCODING_X962_UNCOMPESSED = "X962_UNCOMPRESSED"; + + /** The Constant ENCODING_X962_COMPRESSED. */ public static final String ENCODING_X962_COMPRESSED = "X962_COMPRESSED"; + + /** + * From encoded. + * + * @param keyBytes the encoded key + * @param oid the algorithm OID of the key algorithm + * @param provider the provider of the security implementation + * @return the public key + */ public static PublicKey fromEncoded (byte[] keyBytes, String oid, Provider provider) { PublicKey key = null; @@ -64,12 +88,7 @@ public class ECKeyEncoder { if (key != null) return key; - if (keyBytes[0] == X962_UNCOMPRESSED_POINT_INDICATOR) { - - - - } - + //maybe a compressed X9.62 eliptic key if (keyBytes[0] == X962_ODD || keyBytes[0] == X962_EVEN) { @@ -82,11 +101,10 @@ public class ECKeyEncoder { //get the curve parameters AlgorithmParameters parameters = AlgorithmParameters.getInstance(keyAlgName, provider); parameters.init(new ECGenParameterSpec(curveName)); - ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); - EllipticCurve curve = ecParameters.getCurve(); + ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); //reconstruct the uncompressed version with the curve - byte[] uncompressed = decompressPubkey(keyBytes, curve); + byte[] uncompressed = decompressPubkey(keyBytes, ecParameters); //decode the uncompressed key return fromUncompressedPoint(uncompressed, ecParameters); @@ -125,7 +143,14 @@ public class ECKeyEncoder { - public static byte[] getEncoded(PublicKey key, String encoding){ + /** + * Gets the encoded. + * + * @param key the public key + * @param encoding the encoding ("X509","X962_UNCOMPRESSED","X962_COMPRESSED") + * @return the encoded key + */ + public static byte[] getEncoded(PublicKey key, String encoding){ if (encoding.equals(ENCODING_X509)) { return key.getEncoded(); @@ -142,12 +167,17 @@ public class ECKeyEncoder { if (key instanceof ECPublicKey) { ECPoint point = ((ECPublicKey) key).getW(); + + int fieldSize = (((ECPublicKey)key).getParams().getCurve().getField().getFieldSize() + 7) / 8; + int keySizeBytes = fieldSize + 1; + final byte[] compressed = new byte[keySizeBytes]; + + byte[] x = toUnsignedBytes(point.getAffineX()); BigInteger y = point.getAffineY(); - byte[] compressed = new byte[x.length + 1]; //compression indicator if (y.testBit(0)) { @@ -155,7 +185,7 @@ public class ECKeyEncoder { } else { compressed[0] = 0x02; } - System.arraycopy(x, 0, compressed, 1, x.length); + System.arraycopy(x, 0, compressed, 1 + fieldSize - x.length, x.length); return compressed; } @@ -167,110 +197,117 @@ public class ECKeyEncoder { } - private static ECPublicKey fromUncompressedPoint( - final byte[] uncompressedPoint, final ECParameterSpec params) + /** + * From uncompressed point. + * + * @param encoded the public key in uncompressed encoding + * @param params the elliptic curve parameters + * @return the EC public key + * @throws Exception the exception + */ + private static ECPublicKey fromUncompressedPoint( + final byte[] encoded, final ECParameterSpec params) throws Exception { int offset = 0; - if (uncompressedPoint[offset++] != X962_UNCOMPRESSED_POINT_INDICATOR) { - throw new IllegalArgumentException( - "Invalid uncompressedPoint encoding, no uncompressed point indicator"); + if (encoded[offset++] != X962_UNCOMPRESSED_POINT_INDICATOR) { + throw new IllegalArgumentException("Invalid uncompressedPoint encoding, no uncompressed point indicator"); } int keySizeBytes = (params.getOrder().bitLength() + Byte.SIZE - 1) / Byte.SIZE; - if (uncompressedPoint.length != 1 + 2 * keySizeBytes) { - throw new IllegalArgumentException( - "Invalid uncompressedPoint encoding, not the correct size"); + if (encoded.length != 1 + 2 * keySizeBytes) { + throw new IllegalArgumentException("Invalid uncompressedPoint encoding, not the correct size"); } - final BigInteger x = new BigInteger(1, Arrays.copyOfRange( - uncompressedPoint, offset, offset + keySizeBytes)); + final BigInteger x = new BigInteger(1, Arrays.copyOfRange(encoded, offset, offset + keySizeBytes)); offset += keySizeBytes; - final BigInteger y = new BigInteger(1, Arrays.copyOfRange( - uncompressedPoint, offset, offset + keySizeBytes)); + final BigInteger y = new BigInteger(1, Arrays.copyOfRange(encoded, offset, offset + keySizeBytes)); final ECPoint w = new ECPoint(x, y); final ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(w, params); final KeyFactory keyFactory = KeyFactory.getInstance("EC"); return (ECPublicKey) keyFactory.generatePublic(ecPublicKeySpec); } - private static byte[] toUncompressedPoint(final ECPublicKey publicKey) { - - int keySizeBytes = (publicKey.getParams().getOrder().bitLength() + Byte.SIZE - 1) - / Byte.SIZE; - - final byte[] uncompressedPoint = new byte[1 + 2 * keySizeBytes]; - int offset = 0; - uncompressedPoint[offset++] = 0x04; - - final byte[] x = publicKey.getW().getAffineX().toByteArray(); - if (x.length <= keySizeBytes) { - System.arraycopy(x, 0, uncompressedPoint, offset + keySizeBytes - - x.length, x.length); - } else if (x.length == keySizeBytes + 1 && x[0] == 0) { - System.arraycopy(x, 1, uncompressedPoint, offset, keySizeBytes); - } else { - throw new IllegalStateException("x value is too large"); - } - offset += keySizeBytes; - - final byte[] y = publicKey.getW().getAffineY().toByteArray(); - if (y.length <= keySizeBytes) { - System.arraycopy(y, 0, uncompressedPoint, offset + keySizeBytes - - y.length, y.length); - } else if (y.length == keySizeBytes + 1 && y[0] == 0) { - System.arraycopy(y, 1, uncompressedPoint, offset, keySizeBytes); - } else { - throw new IllegalStateException("y value is too large"); - } + + /** + * To uncompressed point. + * + * @param publicKey the public key + * @return the encoded public key + */ + private static byte[] toUncompressedPoint(final ECPublicKey publicKey) { + + final byte[] xCoordBytes = toUnsignedBytes(publicKey.getW().getAffineX()); + final byte[] yCoordBytes = toUnsignedBytes(publicKey.getW().getAffineY()); + + int fieldSize = (publicKey.getParams().getCurve().getField().getFieldSize() + 7) / 8; + int keySizeBytes = 2 * fieldSize + 1; + final byte[] uncompressedPoint = new byte[keySizeBytes]; + + System.arraycopy(xCoordBytes, 0, uncompressedPoint, 1 + fieldSize - xCoordBytes.length, xCoordBytes.length); + System.arraycopy(yCoordBytes, 0, uncompressedPoint, 1 + 2 * fieldSize - yCoordBytes.length, yCoordBytes.length); + uncompressedPoint[0] = 0x04; return uncompressedPoint; } - static final BigInteger MODULUS = - new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16); - - static final BigInteger POW = MODULUS.add(BigInteger.ONE).shiftRight(2); - // Given a 33-byte compressed public key, this returns a 65-byte uncompressed key. - private static byte[] decompressPubkey(byte[] compressedKey, EllipticCurve curve ) { + + /** + * Decompress public key. + * + * @param compressedKey the compressed public key + * @param ecParameters the elliptic curve parameters + * @return uncompressed encoded public key + */ + private static byte[] decompressPubkey(byte[] compressedKey, ECParameterSpec ecParameters ) { + EllipticCurve curve = ecParameters.getCurve(); + // Check array length and type indicator byte - if (compressedKey.length != 33 || compressedKey[0] != 2 && compressedKey[0] != 3) + if (compressedKey[0] != 2 && compressedKey[0] != 3) { throw new IllegalArgumentException(); + } final byte[] xCoordBytes = Arrays.copyOfRange(compressedKey, 1, compressedKey.length); final BigInteger xCoord = new BigInteger(1, xCoordBytes); // Range [0, 2^256) + ECFieldFp ecf = (ECFieldFp) curve.getField(); + BigInteger modulus = ecf.getP(); + BigInteger pow = modulus.add(BigInteger.ONE).shiftRight(2); + BigInteger temp = xCoord.pow(2).add(curve.getA()); temp = temp.multiply(xCoord); temp = temp.add(curve.getB()); - temp = temp.modPow(POW, MODULUS); - - //temp = sqrtMod(temp.add(curveParamB)); - + temp = temp.modPow(pow, modulus); boolean tempIsOdd = temp.testBit(0); boolean yShouldBeOdd = compressedKey[0] == 3; - if (tempIsOdd != yShouldBeOdd) - temp = temp.negate().mod(MODULUS); + if (tempIsOdd != yShouldBeOdd) { + temp = temp.negate().mod(modulus); + } final BigInteger yCoord = temp; - - // Copy the x coordinate into the new - // uncompressed key, and change the type byte - byte[] result = Arrays.copyOf(compressedKey, 65); + + final byte[] yCoordBytes = toUnsignedBytes(yCoord); + + int fieldSize = (curve.getField().getFieldSize() + 7) / 8; + byte[] result = new byte[2 * fieldSize + 1]; + System.arraycopy(compressedKey, 0,result, 1 + fieldSize - compressedKey.length, compressedKey.length); + System.arraycopy(yCoordBytes, 0,result, 1 + 2 * fieldSize - yCoordBytes.length, yCoordBytes.length); + // set uncompressed key indicator result[0] = 0x04; - // Carefully copy the y coordinate into uncompressed key - final byte[] yCoordBytes = yCoord.toByteArray(); - for (int i = 0; i < 32 && i < yCoordBytes.length; i++) - result[result.length - 1 - i] = yCoordBytes[yCoordBytes.length - 1 - i]; - return result; } + /** + * To unsigned bytes. + * + * @param i the i + * @return the unsigned bytes of the integer + */ private static byte[] toUnsignedBytes(BigInteger i) { byte[] b = i.abs().toByteArray(); //remove top sign bit diff --git a/src/test/java/org/uic/barcode/test/ECKeyEncoderTest521.java b/src/test/java/org/uic/barcode/test/ECKeyEncoderTest521.java new file mode 100644 index 0000000..d70e38e --- /dev/null +++ b/src/test/java/org/uic/barcode/test/ECKeyEncoderTest521.java @@ -0,0 +1,232 @@ +package org.uic.barcode.test; + +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.util.Arrays; + +import org.bouncycastle.asn1.sec.SECNamedCurves; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Before; +import org.junit.Test; +import org.uic.barcode.utils.AlgorithmNameResolver; +import org.uic.barcode.utils.ECKeyEncoder; + +public class ECKeyEncoderTest521 { + + public static Provider provider = null; + + @Before public void initialize() { + + provider = new BouncyCastleProvider(); + Security.addProvider(provider); + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC"); + } + + @Test public void testEncodeCompressed() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp521r1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC"); + + ECPublicKey key = createECPublicKey(name); + + // some additional encoding tricks + byte[] compressedBC = getCompressed(key,name); + String compressedHexBC = Hex.toHexString(compressedBC); + + byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_COMPRESSED); + String compressedHex = Hex.toHexString(publicKeyBytes); + + if (!compressedHexBC.equals(compressedHex)) { + assert(compressedHexBC.equals(compressedHex)); + } + + assert(Arrays.equals(compressedBC, publicKeyBytes)); + + assert(compressedHexBC.equals(compressedHex)); + } + } + + @Test public void testDecodeCompressed() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp521r1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC"); + + ECPublicKey key = createECPublicKey(name); + + // some additional encoding tricks + byte[] compressedBC = getCompressed(key,name); + + PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.35", provider); + + compareKeys((ECPublicKey) publicKey, key); + + } + } + + @Test public void testEncodeUnCompressed() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp521r1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC"); + + ECPublicKey key = createECPublicKey(name); + + byte[] uncompressedBC = getUnCompressed(key,name); + //String uncompressedHex = Hex.toHexString(uncompressedBC); + + byte[] publicKeyUnComp = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_UNCOMPESSED); + + if (!Arrays.equals(uncompressedBC, publicKeyUnComp)) { + assert(Arrays.equals(uncompressedBC, publicKeyUnComp)); + } + + assert(Arrays.equals(uncompressedBC, publicKeyUnComp)); + + } + } + + @Test public void testDecodeUnCompressed() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp521r1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC"); + + ECPublicKey key = createECPublicKey(name); + + // some additional encoding tricks + byte[] compressedBC = getUnCompressed(key,name); + //String compressedHex = Hex.toHexString(compressedBC); + + PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.35", provider); + + compareKeys((ECPublicKey) publicKey, key); + + } + } + + @Test public void testEncodeX509() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp521r1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC"); + + ECPublicKey key = createECPublicKey(name); + + byte[] publicKeyBcX509 = key.getEncoded(); + + byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X509); + assert(Arrays.equals(publicKeyBcX509, publicKeyBytes)); + + } + } + + @Test public void testDecodeX509() throws Exception { + + for (int i = 0; i < 10; i++) { + + String name = "secp521r1"; + + AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.35", "EC"); + + ECPublicKey key = createECPublicKey(name); + + // some additional encoding tricks + byte[] compressedBC = key.getEncoded(); + //String compressedHex = Hex.toHexString(compressedBC); + + PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.35", provider); + + compareKeys((ECPublicKey) publicKey, key); + + } + } + + + + + private ECPublicKey createECPublicKey(String name) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + SecureRandom secureRandom = new SecureRandom(); + X9ECParameters secnamecurves = SECNamedCurves.getByName(name); + ECDomainParameters ecParams = new ECDomainParameters(secnamecurves.getCurve(), secnamecurves.getG(), + secnamecurves.getN(), secnamecurves.getH()); + ECKeyGenerationParameters keyGenParam = new ECKeyGenerationParameters(ecParams, secureRandom); + gen.init(keyGenParam); + + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC"); + ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp521r1"); + kpg.initialize(ecGenParameterSpec); + ECPublicKey key = (ECPublicKey) kpg.generateKeyPair().getPublic(); + return key; + } + + private byte[] getCompressed(ECPublicKey key, String name) { + + byte[] x = key.getW().getAffineX().toByteArray(); + byte[] y = key.getW().getAffineY().toByteArray(); + + // assumes that x and y are (unsigned) big endian encoded + BigInteger xbi = new BigInteger(1, x); + BigInteger ybi = new BigInteger(1, y); + X9ECParameters x9 = ECNamedCurveTable.getByName(name); + ECCurve curve = x9.getCurve(); + ECPoint point = curve.createPoint(xbi, ybi); + + return point.getEncoded(true); + } + + private byte[] getUnCompressed(ECPublicKey key, String name) { + + byte[] x = key.getW().getAffineX().toByteArray(); + byte[] y = key.getW().getAffineY().toByteArray(); + + // assumes that x and y are (unsigned) big endian encoded + BigInteger xbi = new BigInteger(1, x); + BigInteger ybi = new BigInteger(1, y); + X9ECParameters x9 = ECNamedCurveTable.getByName(name); + ECCurve curve = x9.getCurve(); + ECPoint point = curve.createPoint(xbi, ybi); + + return point.getEncoded(false); + + } + + private void compareKeys(ECPublicKey key1, ECPublicKey key2) { + + assert(key1.getW().getAffineX().equals(key2.getW().getAffineX()) ); + assert(key1.getW().getAffineY().equals(key2.getW().getAffineY()) ); + + } + +} -- cgit v1.2.3 From e6e4d8732d75ab521e4ea36d2d25bc6a97791500 Mon Sep 17 00:00:00 2001 From: CGantert345 <57003061+CGantert345@users.noreply.github.com> Date: Tue, 24 May 2022 09:29:57 +0200 Subject: additional test --- .../java/org/uic/barcode/utils/ECKeyEncoder.java | 12 +- .../org/uic/barcode/utils/EllipticCurveNames.java | 1 + ...micFrameDoubleSignatureCompressedCurveTest.java | 168 +++++++++++++++++++++ 3 files changed, 175 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/uic/barcode/test/DynamicFrameDoubleSignatureCompressedCurveTest.java diff --git a/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java b/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java index 705b178..e1662a7 100644 --- a/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java +++ b/src/main/java/org/uic/barcode/utils/ECKeyEncoder.java @@ -97,8 +97,7 @@ public class ECKeyEncoder { //we need to know the curve! String curveName = EllipticCurveNames.getInstance().getName(oid); - - //get the curve parameters + AlgorithmParameters parameters = AlgorithmParameters.getInstance(keyAlgName, provider); parameters.init(new ECGenParameterSpec(curveName)); ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); @@ -107,7 +106,7 @@ public class ECKeyEncoder { byte[] uncompressed = decompressPubkey(keyBytes, ecParameters); //decode the uncompressed key - return fromUncompressedPoint(uncompressed, ecParameters); + return fromUncompressedPoint(uncompressed, ecParameters, provider); } catch (Exception e) { key = null; @@ -130,7 +129,7 @@ public class ECKeyEncoder { ECParameterSpec ecParameters = parameters.getParameterSpec(ECParameterSpec.class); //decode the uncompressed key - return fromUncompressedPoint(keyBytes, ecParameters); + return fromUncompressedPoint(keyBytes, ecParameters, provider); } catch(Exception e) { //failed @@ -148,6 +147,7 @@ public class ECKeyEncoder { * * @param key the public key * @param encoding the encoding ("X509","X962_UNCOMPRESSED","X962_COMPRESSED") + * @param provider * @return the encoded key */ public static byte[] getEncoded(PublicKey key, String encoding){ @@ -206,7 +206,7 @@ public class ECKeyEncoder { * @throws Exception the exception */ private static ECPublicKey fromUncompressedPoint( - final byte[] encoded, final ECParameterSpec params) + final byte[] encoded, final ECParameterSpec params, Provider provider) throws Exception { int offset = 0; @@ -226,7 +226,7 @@ public class ECKeyEncoder { final BigInteger y = new BigInteger(1, Arrays.copyOfRange(encoded, offset, offset + keySizeBytes)); final ECPoint w = new ECPoint(x, y); final ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(w, params); - final KeyFactory keyFactory = KeyFactory.getInstance("EC"); + final KeyFactory keyFactory = KeyFactory.getInstance("EC",provider); return (ECPublicKey) keyFactory.generatePublic(ecPublicKeySpec); } diff --git a/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java b/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java index 41353b1..706d3c3 100644 --- a/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java +++ b/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java @@ -39,6 +39,7 @@ public class EllipticCurveNames { me.oitToName.put("1.3.132.0.38", "sect571k1"); me.oitToName.put("1.3.132.0.39", "sect571r1"); me.oitToName.put("1.3.132.0.10", "secp256k1"); + me.oitToName.put("1.2.840.10045.3.1.7", "secp256r1"); } return me; diff --git a/src/test/java/org/uic/barcode/test/DynamicFrameDoubleSignatureCompressedCurveTest.java b/src/test/java/org/uic/barcode/test/DynamicFrameDoubleSignatureCompressedCurveTest.java new file mode 100644 index 0000000..3a3f7d2 --- /dev/null +++ b/src/test/java/org/uic/barcode/test/DynamicFrameDoubleSignatureCompressedCurveTest.java @@ -0,0 +1,168 @@ +package org.uic.barcode.test; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; +import java.security.SignatureException; +import java.security.spec.ECGenParameterSpec; +import java.util.Arrays; +import java.util.zip.DataFormatException; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.junit.Before; +import org.junit.Test; +import org.uic.barcode.Decoder; +import org.uic.barcode.Encoder; +import org.uic.barcode.dynamicFrame.Constants; +import org.uic.barcode.dynamicFrame.api.IData; +import org.uic.barcode.logger.LoggerFactory; +import org.uic.barcode.test.utils.Level2TestDataFactory; +import org.uic.barcode.test.utils.SimpleUICTestTicket; +import org.uic.barcode.ticket.EncodingFormatException; +import org.uic.barcode.ticket.api.spec.IUicRailTicket; +import org.uic.barcode.utils.ECKeyEncoder; +import org.uic.barcode.utils.SecurityUtils; + +public class DynamicFrameDoubleSignatureCompressedCurveTest { + + public String signatureAlgorithmOID = null; + public String elipticCurve = null; + public String keyPairAlgorithmOID = null; + + public KeyPair keyPairLevel1 = null; + public KeyPair keyPairLevel2 = null; + + public IUicRailTicket testFCBticket = null; + + public Provider provider = null; + + + @Before public void initialize() { + + LoggerFactory.setActivateConsoleLog(true); + + signatureAlgorithmOID = Constants.ECDSA_SHA256; + keyPairAlgorithmOID = Constants.KG_EC_256; + elipticCurve = "secp256r1"; + + testFCBticket = SimpleUICTestTicket.getUicTestTicket(); + + provider = new BouncyCastleProvider(); + Security.addProvider(new BouncyCastleProvider()); + + try { + keyPairLevel1 = generateECKeys(keyPairAlgorithmOID, elipticCurve); + keyPairLevel2 = generateECKeys(keyPairAlgorithmOID, elipticCurve); + } catch (Exception e) { + assert(false); + } + + assert(keyPairLevel1 != null); + + assert(keyPairLevel2 != null); + + } + + + + @Test public void testDynamicHeaderBarcodeDecoding() { + + IUicRailTicket ticket = testFCBticket; + + Encoder enc = null; + + try { + enc = new Encoder(ticket, null, Encoder.UIC_BARCODE_TYPE_DOSIPAS, 1, 13); + } catch (IOException | EncodingFormatException e1) { + assert(false); + } + + assert(enc != null); + + try { + enc.setLevel1Algs(signatureAlgorithmOID, keyPairAlgorithmOID); + enc.setLevel2Algs(signatureAlgorithmOID, keyPairAlgorithmOID,keyPairLevel2.getPublic(), ECKeyEncoder.ENCODING_X962_COMPRESSED); + enc.signLevel1("1080", keyPairLevel1.getPrivate(), signatureAlgorithmOID, "1"); + } catch (Exception e) { + assert(false); + } + + assert(enc != null); + + + IData level2Data = Level2TestDataFactory.getLevel2SimpleTestData(); + try { + enc.setLevel2Data(level2Data); + enc.signLevel2(keyPairLevel2.getPrivate()); + } catch (Exception e) { + assert(false); + } + + + byte[] encoded = null; + try { + encoded = enc.encode(); + } catch (Exception e) { + assert(false); + } + + assert(encoded != null); + + Decoder dec = null; + try { + dec = new Decoder(encoded); + } catch (IOException e) { + assert(false); + } catch (EncodingFormatException e) { + assert(false); + } catch (DataFormatException e) { + assert(false); + } + assert(dec != null); + + int signatureCheck = 0; + try { + signatureCheck = dec.validateLevel1(keyPairLevel1.getPublic(), null); + } catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException | IllegalArgumentException + | UnsupportedOperationException | IOException | EncodingFormatException e) { + assert(false); + } + assert(signatureCheck == Constants.LEVEL1_VALIDATION_OK); + + signatureCheck = 0; + try { + signatureCheck = dec.validateLevel2(); + } catch (Exception e) { + assert(false); + } + assert(signatureCheck == Constants.LEVEL2_VALIDATION_OK); + + IData level2DataDec = dec.getLevel2Data(); + + assert(level2Data.getFormat().equals(level2DataDec.getFormat())); + assert(Arrays.equals(level2Data.getData(),level2DataDec.getData())); + + SimpleUICTestTicket.compare(ticket, dec.getUicTicket()); + + } + + + public KeyPair generateECKeys(String keyAlgorithmOid, String curve) throws Exception{ + + //ECNamedCurveGenParameterSpec namedParamSpec = new ECNamedCurveGenParameterSpec(elipticCurve); + + ECGenParameterSpec namedParamSpec = new ECGenParameterSpec(elipticCurve); + KeyPairGenerator ecKPGen = KeyPairGenerator.getInstance("EC", "BC"); + ecKPGen.initialize(namedParamSpec, new SecureRandom()); + KeyPair keyPair = ecKPGen.generateKeyPair(); + KeyPair kp = new KeyPair(SecurityUtils.convert(keyPair.getPublic(), provider),SecurityUtils.convert(keyPair.getPrivate(), provider)); + return kp; + } + + +} -- cgit v1.2.3 From 2a171b6c616e1b726591937880858081e37964c4 Mon Sep 17 00:00:00 2001 From: CGantert345 <57003061+CGantert345@users.noreply.github.com> Date: Tue, 24 May 2022 12:11:45 +0200 Subject: curve names added --- .../org/uic/barcode/utils/EllipticCurveNames.java | 60 +++++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java b/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java index 706d3c3..1bff0c0 100644 --- a/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java +++ b/src/main/java/org/uic/barcode/utils/EllipticCurveNames.java @@ -25,22 +25,68 @@ public class EllipticCurveNames { if (me == null) { me = new EllipticCurveNames(); + me.oitToName.put("1.2.840.10045.3.0.4", "c2pnb176w1"); + me.oitToName.put("1.2.840.10045.3.0.1", "c2pnb163v1"); + me.oitToName.put("1.2.840.10045.3.0.2", "c2pnb163v2"); + me.oitToName.put("1.2.840.10045.3.0.3", "c2pnb163v3"); + me.oitToName.put("1.2.840.10045.3.0.10","c2pnb208w1"); + me.oitToName.put("1.2.840.10045.3.0.7", "c2tnb191v3"); + me.oitToName.put("1.2.840.10045.3.0.6", "c2tnb191v2"); + me.oitToName.put("1.2.840.10045.3.0.5", "c2tnb191v1"); + me.oitToName.put("1.2.840.10045.3.0.13","c2tnb239v3"); + me.oitToName.put("1.2.840.10045.3.0.12","c2tnb239v2"); + me.oitToName.put("1.2.840.10045.3.0.11","c2tnb239v1"); + me.oitToName.put("1.2.840.10045.3.0.16","c2pnb272w1"); + me.oitToName.put("1.2.840.10045.3.0.17","c2pnb304w1"); + me.oitToName.put("1.2.840.10045.3.0.19","c2pnb368w1"); + me.oitToName.put("1.2.840.10045.3.0.18","c2tnb359v1"); + me.oitToName.put("1.2.840.10045.3.0.20","c2tnb431r1"); + me.oitToName.put("1.2.840.10045.3.0.8", "c2onb191v4"); + me.oitToName.put("1.2.840.10045.3.0.9", "c2onb191v5"); + me.oitToName.put("1.2.840.10045.3.0.14","c2onb239v4"); + me.oitToName.put("1.2.840.10045.3.0.15","c2onb239v5"); + me.oitToName.put("1.2.840.10045.3.1.1", "secp192r1"); + //me.oitToName.put("1.2.840.10045.3.1.1", "prime192v1"); + me.oitToName.put("1.2.840.10045.3.1.2", "prime192v2"); + me.oitToName.put("1.2.840.10045.3.1.3", "prime192v3"); + me.oitToName.put("1.2.840.10045.3.1.4", "prime239v1"); + me.oitToName.put("1.2.840.10045.3.1.5", "prime239v2"); + me.oitToName.put("1.2.840.10045.3.1.6", "prime239v3"); + me.oitToName.put("1.2.840.10045.3.1.7", "secp256r1"); + //me.oitToName.put("1.2.840.10045.3.1.7", "prime256v1"); + me.oitToName.put("1.3.132.0.1", "sect163k1"); + me.oitToName.put("1.3.132.0.2", "sect163r1"); + me.oitToName.put("1.3.132.0.3", "sect239k1"); + me.oitToName.put("1.3.132.0.4", "sect113r1"); + me.oitToName.put("1.3.132.0.5", "sect113r2"); + me.oitToName.put("1.3.132.0.6", "secp112r1"); + me.oitToName.put("1.3.132.0.7", "secp112r2"); + me.oitToName.put("1.3.132.0.8", "secp160r1"); + me.oitToName.put("1.3.132.0.9", "secp160k1"); + me.oitToName.put("1.3.132.0.10", "secp256k1"); me.oitToName.put("1.3.132.0.15", "sect163r2"); - me.oitToName.put("1.3.132.0.33", "secp224r1"); - me.oitToName.put("1.3.132.0.26", "sect233k1"); - me.oitToName.put("1.3.132.0.27", "sect233r1"); me.oitToName.put("1.3.132.0.16", "sect283k1"); me.oitToName.put("1.3.132.0.17", "sect283r1"); + me.oitToName.put("1.3.132.0.22", "sect131r1"); + me.oitToName.put("1.3.132.0.23", "sect131r2"); + me.oitToName.put("1.3.132.0.24", "sect193r1"); + me.oitToName.put("1.3.132.0.25", "sect193r2"); + me.oitToName.put("1.3.132.0.26", "sect233k1"); + me.oitToName.put("1.3.132.0.27", "sect233r1"); + me.oitToName.put("1.3.132.0.28", "secp128r1"); + me.oitToName.put("1.3.132.0.29", "secp128r2"); + me.oitToName.put("1.3.132.0.30", "secp160r2"); + me.oitToName.put("1.3.132.0.31", "secp192k1"); + me.oitToName.put("1.3.132.0.32", "secp224k1"); + me.oitToName.put("1.3.132.0.33", "secp224r1"); me.oitToName.put("1.3.132.0.34", "secp384r1"); + me.oitToName.put("1.3.132.0.35", "secp521r1"); me.oitToName.put("1.3.132.0.36", "sect409k1"); me.oitToName.put("1.3.132.0.37", "sect409r1"); - me.oitToName.put("1.3.132.0.35", "secp521r1"); me.oitToName.put("1.3.132.0.38", "sect571k1"); me.oitToName.put("1.3.132.0.39", "sect571r1"); - me.oitToName.put("1.3.132.0.10", "secp256k1"); - me.oitToName.put("1.2.840.10045.3.1.7", "secp256r1"); - + } return me; } -- cgit v1.2.3 From 147ae5b4844bc60060705ac6f2144db988edfa61 Mon Sep 17 00:00:00 2001 From: CGantert345 <57003061+CGantert345@users.noreply.github.com> Date: Thu, 9 Jun 2022 10:16:18 +0200 Subject: Delete DecodeDB9EuroTicketTest.java --- .../ticketTestDB/DecodeDB9EuroTicketTest.java | 133 --------------------- 1 file changed, 133 deletions(-) delete mode 100644 src/test/java/org/uic/barcode/ticketTestDB/DecodeDB9EuroTicketTest.java diff --git a/src/test/java/org/uic/barcode/ticketTestDB/DecodeDB9EuroTicketTest.java b/src/test/java/org/uic/barcode/ticketTestDB/DecodeDB9EuroTicketTest.java deleted file mode 100644 index cc69aa0..0000000 --- a/src/test/java/org/uic/barcode/ticketTestDB/DecodeDB9EuroTicketTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.uic.barcode.ticketTestDB; - - -import java.util.TimeZone; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.uic.barcode.Decoder; -import org.uic.barcode.asn1.uper.UperEncoder; -import org.uic.barcode.logger.LoggerFactory; -import org.uic.barcode.staticFrame.ticketLayoutBarcode.TicketLayout; -import org.uic.barcode.ticket.api.spec.IOpenTicket; -import org.uic.barcode.ticket.api.spec.IPassengerType; -import org.uic.barcode.ticket.api.spec.ITariff; -import org.uic.barcode.ticket.api.spec.ITrainLink; -import org.uic.barcode.ticket.api.spec.ITraveler; -import org.uic.barcode.ticket.api.spec.IUicRailTicket; - -public class DecodeDB9EuroTicketTest { - - TimeZone defaulttimeZone = null; - - /** - * Prepare tickets. - */ - @Before public void prepare() { - - LoggerFactory.setActivateConsoleLog(true); - - defaulttimeZone = TimeZone.getDefault(); - //decode in local CET time zone - TimeZone.setDefault(TimeZone.getTimeZone("CET")); - } - - - /** - * clean up - */ - @After public void resetTimeZone() { - TimeZone.setDefault(defaulttimeZone); - } - - @Test - public void testDecoder() throws Exception { - - - byte[] content = UperEncoder.bytesFromHexString(getEncodingV2Hex()); - - // try to decode - Decoder decoder = new Decoder(content); - TicketLayout layout = decoder.getLayout(); - IUicRailTicket ticket = decoder.getUicTicket(); - - - Assert.assertNotNull(ticket); - - Assert.assertNotNull(ticket.getDocumentData()); - Assert.assertNotNull(ticket.getIssuerDetails()); - Assert.assertNotNull(ticket.getTravelerDetails()); - - assert(ticket.getIssuerDetails().getIssuer().equals("1080")); - assert(ticket.getIssuerDetails().getIssuerPNR().equals("D260V48G")); - String issuingDate = ticket.getIssuerDetails().getIssuingDate().toString(); - assert(issuingDate.equals("Fri Oct 30 11:50:00 CET 2020")); - assert(ticket.getIssuerDetails().getSecurityProvider().equals("1080")); - assert(ticket.getIssuerDetails().isSecurePaperTicket() == false); - assert(ticket.getIssuerDetails().isActivated() == true); - assert(ticket.getIssuerDetails().isSpecimen() == false); - - assert(ticket.getTravelerDetails().getTravelers().size() == 1); - ITraveler traveler = ticket.getTravelerDetails().getTravelers().iterator().next(); - assert(traveler.getFirstName().equals("Karsten")); - assert(traveler.getLastName().equals("Will")); - assert(traveler.isTicketHolder() == true); - - assert(ticket.getDocumentData().size() == 1); - IOpenTicket openTicket = (IOpenTicket) ticket.getDocumentData().iterator().next(); - Assert.assertNotNull(openTicket.getValidRegionList()); - assert(openTicket.getReference().equals("CN0CTUMY")); - String fromDate = openTicket.getValidFrom().toString(); - assert(fromDate.equals("Thu Nov 05 00:00:00 CET 2020")); - assert(openTicket.getValidFromUTCoffset() == -4L); - String toDate = openTicket.getValidUntil().toString(); - assert(toDate.equals("Fri Nov 06 10:00:00 CET 2020")); - assert(openTicket.getValidUntilUTCoffset() == -4L); - - Assert.assertNotNull(openTicket.getTariffs()); - assert(openTicket.getTariffs().size() == 1); - ITariff tariff = openTicket.getTariffs().iterator().next(); - assert(tariff.getNumberOfPassengers() == 1); - assert(tariff.getPassengerType().equals(IPassengerType.adult)); - assert(tariff.getTariffDescription().equals("Super Sparpreis")); - - - ITrainLink tl = (ITrainLink) openTicket.getValidRegionList().iterator().next(); - Assert.assertNotNull(tl); - assert(tl.getTrain().equals("ICE973")); - String departureDate = tl.getDepartureDateTime().toString(); - assert(departureDate.equals("Fri Nov 06 11:58:00 CET 2020")); - Assert.assertNull(layout); - Assert.assertNotNull(decoder); - } - - public static String getEncodingV2Hex() { - - return "2355543032323038303030303033000000005C57C2"+ - "8521C3A1C3BCC29D5DC3960E2CC2897C18C390534"+ - "EC2AFC387C388703AC2B367C39FC3BD55C2B70000"+ - "0000422E1BC29F1CC3B9265E43C2B7493B2B51C39"+ - "2C291007CC2B5C2870D3A2EC3B3C38249C38FC2B3"+ - "3032343778C29C0BC28DC3B770757431303430303"+ - "53534343656400379C2A539394049132303232343"+ - "430353C283C3943CC2905068C2BCC29BC28F6B045"+ - "0C29BC291C28141C28101430AC3974C76C3BFC39C"+ - "C2BCC38CC292C38C420D2626090E064715C3AEC29"+ - "6060FC3A66E29C28D74C2BFC288C29277C391C2BB"+ - "C397C39DC289C2AC642E4A2D3978C39AC3ACC38D5"+ - "CC383C2A4C2AB0BC3B27CC396C38DC2B04CC2BB3B"+ - "79C2994EC3B4265EC3A7C28CC3845C1D05C2A7C38"+ - "4C28CC2BCC28CC3BC340108C38F2D27C3BFC3B0C3"+ - "BCC28CC384C2B4C394C2BC603D15C296C38606763"+ - "1C293C380C292C2B069C38FC297C2851D4B136B57"+ - "776209572F13336B370B7B16C2AEC2A032C3A508C"+ - "283C282C388C3846561C2B9C2B337255DC38D33C2"+ - "8BC29459C29B395B78C3AAC28EC399C39BC28E6D5"+ - "D17C2937BC38732C3A73CC2B73A6FC38BC29D1D45"+ - "4FC29BC2AEC3B1C38CC2B1C2883AC39B6CC38E7B6"+ - "D7B16030046115A6F"; - } - -} \ No newline at end of file -- cgit v1.2.3